#ifndef MSG_TOOL_H
#define MSG_TOOL_H

#include <assert.h>
#include <string.h>

const long MAX_MSGLEN = 65536;
const long MAX_BINLEN = 65536*8 + 16;

long getBinaryLegnth(int msglen);
int getMessageLength(long binlen);
char* createBinFromMsg(const char *msg, int msglen, long *binlen);
char* createMsgFromBin(const char *bin, long binlen, int *msglen);
long readFile(char* fname, char** pmsg);
long writeFile(char* fname, char* msg, int msglen);

long getBinaryLength(int msglen) {
	assert(msglen < MAX_MSGLEN);
	return (long)msglen *8+16;
}

int getMessageLength(long binlen) {
	assert((binlen >= 16) && (binlen < MAX_BINLEN));
	return (binlen-16) / 8;
}

static unsigned char get8Bit(const char* buf) {
	unsigned char value = 0;
	signed int i;
	for (i = 7;i >= 0;i--) {
		value = value*2 + buf[i];
	}
	return value;
}

static void copy8Bit(char value, char* buf) {
	int i;
	for (i = 0;i < 8;i++) {
		buf[i] = value & 1;
		value = value >> 1;
		/*
		buf[i] = abs(value % 2);
		value = value / 2;
		*/
	}
}

char* createMsgFromBin(const char *bin, long binlen, int *msglen) {
	long hbit,lbit,size,i;
	int max_size;
	char* msg;
	assert( (bin != NULL) && (binlen <= MAX_BINLEN) );
	hbit = get8Bit(bin);
	lbit = get8Bit(bin+8);
	size = hbit * 256 + lbit;
#ifdef VERBOSE
	printf("%d,%d,%d\n",hbit,lbit,size);
#endif
	max_size = getMessageLength(binlen);
	if (size > max_size) {
		printf("detected size mismatch, possibly part of message embeded.");
		printf("fix %d to %d\n",size, max_size);
		size = max_size;
	}
	*msglen = size;
	msg = (char*) malloc((size+1)*sizeof(char));
	for (i = 0;i < size;i++) {
		msg[i] = get8Bit(bin+16+i*8);
	}
	msg[size] = '\0';
	return msg;
}

char* createBinFromMsg(const char *msg, int msglen, long *binlen) {
	long hbit,lbit,i,len;
	char *bin;
	if (msglen > MAX_MSGLEN)
		msglen = MAX_MSGLEN - 1;
	assert( (msg != NULL) && (msglen < MAX_MSGLEN) );
	len = getBinaryLength(msglen);
    *binlen = len;
	bin = (char*) malloc(len * sizeof(char));
	hbit = msglen / 256 % 256;
	copy8Bit(hbit,bin);
	lbit = msglen % 256;
	copy8Bit(lbit,bin+8);
	for (i = 0;i < msglen;i++) {
		copy8Bit(msg[i],bin+16+i*8);
	}
#ifdef VERBOSE
	printf("%d,%d,%d,%d\n",hbit,lbit,get8Bit(bin),get8Bit(bin+8));
#endif
	return bin;
}

long readFile(char* fname, char** pmsg) {
	FILE *fmsg = fopen(fname, "rb");
	long msglen, count = 0;
	char* msg;
	if (fmsg == NULL) {
		fprintf(stderr,"Cannot open message file");
		return -3;
	}
	// find size of the file
	if (fseek(fmsg,0,SEEK_END) != 0) {
		fprintf(stderr,"fseek failed.");
		return -1;
	}
	msglen = ftell(fmsg);
	printf("msglen = %d\n",msglen);
	*pmsg = (char*) malloc((msglen+1)*sizeof(char));
	msg = *pmsg;
	assert((msg != NULL) && (msglen >= 0));
	fseek(fmsg, 0, SEEK_SET);
	while (count < msglen) {
		int read_byte = fread(&msg[count], sizeof(char), msglen-count, fmsg);
		if (read_byte > 0)
			count += read_byte;
		else
			break;
	}
	msglen = count;
	msg[msglen] = '\0';
	fclose(fmsg);
	return msglen;
}

long writeFile(char* fname, char* msg, int msglen) {
	FILE* outfile = NULL;
	long count = 0;
	if ((outfile = fopen(fname, "wb")) == NULL) {
		fprintf(stderr,"Cannot open output file");
		return -3;
	}
	while (count < msglen) {
		int write_byte = fwrite(msg, sizeof(char), msglen, outfile);
		if (write_byte > 0)
			count += write_byte;
		else
			break;
	}
	fclose(outfile);
	return count;
}
#endif